# -*- coding: utf-8 -*-
"""
评价控制器

处理课程评价的核心业务逻辑：
- 创建评价记录
- 提交学员评价
- 提交教练评价
- 修改评价内容
- 查询评价记录
- 评价统计分析
"""

from datetime import datetime, timedelta
from decimal import Decimal
from typing import Optional, Dict, Any, List, Tuple
from flask import current_app
from sqlalchemy.exc import SQLAlchemyError
from sqlalchemy import func, and_, or_
from sqlalchemy.orm import joinedload

from app import db
from app.models.evaluation import Evaluation
from app.models.reservation import Reservation
from app.models.user import User
from app.utils.exceptions import BusinessError, ValidationError


class EvaluationController:
    """评价控制器"""

    @staticmethod
    def validate_evaluation_permission(reservation_id: int, user_id: int, user_type: str) -> Dict[str, Any]:
        """
        验证评价权限

        Args:
            reservation_id: 预约ID
            user_id: 用户ID
            user_type: 用户类型 ('student' 或 'coach')

        Returns:
            验证结果和预约信息
        """
        try:
            # 查询预约记录
            reservation = Reservation.query.get(reservation_id)
            if not reservation:
                return {
                    'valid': False,
                    'message': '预约记录不存在',
                    'reservation': None
                }

            # 验证预约状态
            if reservation.status != 'completed':
                return {
                    'valid': False,
                    'message': '只有已完成的课程才能评价',
                    'reservation': reservation
                }

            # 验证用户权限
            if user_type == 'student':
                if reservation.student_id != user_id:
                    return {
                        'valid': False,
                        'message': '您无权评价此课程',
                        'reservation': reservation
                    }
            elif user_type == 'coach':
                if reservation.coach_id != user_id:
                    return {
                        'valid': False,
                        'message': '您无权评价此课程',
                        'reservation': reservation
                    }
            else:
                return {
                    'valid': False,
                    'message': '无效的用户类型',
                    'reservation': reservation
                }

            # 检查是否已经评价过
            existing_evaluation = Evaluation.query.filter_by(reservation_id=reservation_id).first()
            if existing_evaluation:
                # 根据用户类型检查是否已评价
                if user_type == 'student' and existing_evaluation.student_rating is not None:
                    return {
                        'valid': False,
                        'message': '您已经评价过此课程，可以在评价列表中修改',
                        'reservation': reservation
                    }
                elif user_type == 'coach' and existing_evaluation.coach_rating is not None:
                    return {
                        'valid': False,
                        'message': '您已经评价过此课程，可以在评价列表中修改',
                        'reservation': reservation
                    }

            return {
                'valid': True,
                'message': '验证通过',
                'reservation': reservation,
                'existing_evaluation': existing_evaluation
            }

        except Exception as e:
            current_app.logger.error(f"验证评价权限时发生错误: {str(e)}")
            return {
                'valid': False,
                'message': f'系统错误：{str(e)}',
                'reservation': None
            }

    @staticmethod
    def create_evaluation(reservation_id: int, evaluator_id: int, evaluator_type: str,
                         rating: int, comment: str = None) -> Dict[str, Any]:
        """
        创建或更新评价记录

        Args:
            reservation_id: 预约ID
            evaluator_id: 评价人ID
            evaluator_type: 评价人类型 ('student' 或 'coach')
            rating: 评分 (1-5)
            comment: 评价内容

        Returns:
            创建结果信息
        """
        try:
            # 验证预约是否存在且已完成
            reservation = Reservation.query.get(reservation_id)
            if not reservation:
                return {'success': False, 'message': '预约记录不存在'}

            if reservation.status != 'completed':
                return {'success': False, 'message': '只有已完成的课程才能评价'}

            # 验证评价人权限
            if evaluator_type == 'student':
                if reservation.student_id != evaluator_id:
                    return {'success': False, 'message': '您无权评价此课程'}
            elif evaluator_type == 'coach':
                if reservation.coach_id != evaluator_id:
                    return {'success': False, 'message': '您无权评价此课程'}
            else:
                return {'success': False, 'message': '无效的评价人类型'}

            # 验证评分范围
            if not (1 <= rating <= 5):
                return {'success': False, 'message': '评分必须在1-5之间'}

            # 查找或创建评价记录
            evaluation = Evaluation.query.filter_by(reservation_id=reservation_id).first()

            if not evaluation:
                # 创建新的评价记录
                evaluation = Evaluation(
                    reservation_id=reservation_id,
                    student_id=reservation.student_id,
                    coach_id=reservation.coach_id
                )
                db.session.add(evaluation)

            # 根据评价人类型设置对应字段
            current_time = datetime.now()

            if evaluator_type == 'student':
                if evaluation.student_rating is not None:
                    return {'success': False, 'message': '您已经评价过此课程，请使用修改功能'}

                evaluation.student_rating = rating
                evaluation.student_comment = comment
                evaluation.student_submitted_at = current_time

            else:  # coach
                if evaluation.coach_rating is not None:
                    return {'success': False, 'message': '您已经评价过此课程，请使用修改功能'}

                evaluation.coach_rating = rating
                evaluation.coach_comment = comment
                evaluation.coach_submitted_at = current_time

            db.session.commit()

            return {
                'success': True,
                'message': '评价提交成功',
                'evaluation_id': evaluation.id
            }

        except Exception as e:
            db.session.rollback()
            current_app.logger.error(f"创建评价时发生错误: {str(e)}")
            return {'success': False, 'message': f'提交评价失败：{str(e)}'}

    @staticmethod
    def submit_student_evaluation(evaluation_id: int, student_id: int, rating: int,
                                 comment: str = None) -> Dict[str, Any]:
        """
        提交学员评价

        Args:
            evaluation_id: 评价ID
            student_id: 学员ID
            rating: 评分（1-5）
            comment: 评价内容

        Returns:
            提交结果信息

        Raises:
            BusinessError: 业务逻辑错误
        """
        try:
            # 获取评价记录
            evaluation = Evaluation.query.get(evaluation_id)
            if not evaluation:
                raise BusinessError("评价记录不存在")

            # 验证权限
            if evaluation.student_id != student_id:
                raise BusinessError("无权限提交此评价")

            # 验证是否可以评价
            if not evaluation.can_student_evaluate():
                raise BusinessError("您已经提交过评价了")

            # 验证评分范围
            if not (1 <= rating <= 5):
                raise ValidationError("评分必须在1-5之间")

            # 提交评价
            success, message = evaluation.submit_student_evaluation(rating, comment)
            if not success:
                raise ValidationError(message)

            db.session.commit()

            current_app.logger.info(
                f"学员评价提交成功 - 评价ID: {evaluation_id}, 学员ID: {student_id}, "
                f"评分: {rating}"
            )

            return {
                'success': True,
                'evaluation_id': evaluation.id,
                'rating': rating,
                'comment': comment,
                'submitted_at': evaluation.student_submitted_at.isoformat(),
                'is_completed': evaluation.is_completed(),
                'message': '评价提交成功'
            }

        except (BusinessError, ValidationError):
            raise
        except SQLAlchemyError as e:
            db.session.rollback()
            current_app.logger.error(
                f"提交学员评价失败 - 评价ID: {evaluation_id}, 错误: {str(e)}"
            )
            raise BusinessError("提交评价失败，请稍后重试")

    @staticmethod
    def submit_coach_evaluation(evaluation_id: int, coach_id: int, rating: int,
                               comment: str = None) -> Dict[str, Any]:
        """
        提交教练评价

        Args:
            evaluation_id: 评价ID
            coach_id: 教练ID
            rating: 评分（1-5）
            comment: 评价内容

        Returns:
            提交结果信息

        Raises:
            BusinessError: 业务逻辑错误
        """
        try:
            # 获取评价记录
            evaluation = Evaluation.query.get(evaluation_id)
            if not evaluation:
                raise BusinessError("评价记录不存在")

            # 验证权限
            if evaluation.coach_id != coach_id:
                raise BusinessError("无权限提交此评价")

            # 验证是否可以评价
            if not evaluation.can_coach_evaluate():
                raise BusinessError("您已经提交过评价了")

            # 验证评分范围
            if not (1 <= rating <= 5):
                raise ValidationError("评分必须在1-5之间")

            # 提交评价
            success, message = evaluation.submit_coach_evaluation(rating, comment)
            if not success:
                raise ValidationError(message)

            db.session.commit()

            current_app.logger.info(
                f"教练评价提交成功 - 评价ID: {evaluation_id}, 教练ID: {coach_id}, "
                f"评分: {rating}"
            )

            return {
                'success': True,
                'evaluation_id': evaluation.id,
                'rating': rating,
                'comment': comment,
                'submitted_at': evaluation.coach_submitted_at.isoformat(),
                'is_completed': evaluation.is_completed(),
                'message': '评价提交成功'
            }

        except (BusinessError, ValidationError):
            raise
        except SQLAlchemyError as e:
            db.session.rollback()
            current_app.logger.error(
                f"提交教练评价失败 - 评价ID: {evaluation_id}, 错误: {str(e)}"
            )
            raise BusinessError("提交评价失败，请稍后重试")

    @staticmethod
    def update_evaluation(evaluation_id: int, user_id: int, user_type: str,
                        rating: int, comment: str = None) -> Dict[str, Any]:
        """
        修改评价（统一处理学员和教练的修改）

        Args:
            evaluation_id: 评价ID
            user_id: 用户ID
            user_type: 用户类型 ('student' 或 'coach')
            rating: 新评分
            comment: 新评价内容

        Returns:
            修改结果信息
        """
        try:
            # 获取评价记录
            evaluation = Evaluation.query.get(evaluation_id)
            if not evaluation:
                return {'success': False, 'message': '评价记录不存在'}

            # 验证权限和修改时限
            if user_type == 'student':
                if evaluation.student_id != user_id:
                    return {'success': False, 'message': '无权限修改此评价'}

                if not evaluation.has_student_evaluation():
                    return {'success': False, 'message': '您还未提交评价，请先提交评价'}

                if evaluation.student_submitted_at:
                    time_diff = datetime.now() - evaluation.student_submitted_at
                    if time_diff > timedelta(hours=24):
                        return {'success': False, 'message': '评价提交超过24小时，无法修改'}

                # 更新学员评价
                evaluation.student_rating = rating
                evaluation.student_comment = comment
                evaluation.student_submitted_at = datetime.now()

            elif user_type == 'coach':
                if evaluation.coach_id != user_id:
                    return {'success': False, 'message': '无权限修改此评价'}

                if not evaluation.has_coach_evaluation():
                    return {'success': False, 'message': '您还未提交评价，请先提交评价'}

                if evaluation.coach_submitted_at:
                    time_diff = datetime.now() - evaluation.coach_submitted_at
                    if time_diff > timedelta(hours=24):
                        return {'success': False, 'message': '评价提交超过24小时，无法修改'}

                # 更新教练评价
                evaluation.coach_rating = rating
                evaluation.coach_comment = comment
                evaluation.coach_submitted_at = datetime.now()
            else:
                return {'success': False, 'message': '无效的用户类型'}

            # 验证评分范围
            if not (1 <= rating <= 5):
                return {'success': False, 'message': '评分必须在1-5之间'}

            db.session.commit()

            return {
                'success': True,
                'message': '评价修改成功',
                'evaluation_id': evaluation.id
            }

        except Exception as e:
            db.session.rollback()
            current_app.logger.error(f"修改评价失败 - 评价ID: {evaluation_id}, 错误: {str(e)}")
            return {'success': False, 'message': f'修改评价失败：{str(e)}'}

    @staticmethod
    def update_coach_evaluation(evaluation_id: int, coach_id: int, rating: int,
                               comment: str = None) -> Dict[str, Any]:
        """
        修改教练评价（限时修改）

        Args:
            evaluation_id: 评价ID
            coach_id: 教练ID
            rating: 新评分
            comment: 新评价内容

        Returns:
            修改结果信息

        Raises:
            BusinessError: 业务逻辑错误
        """
        try:
            # 获取评价记录
            evaluation = Evaluation.query.get(evaluation_id)
            if not evaluation:
                raise BusinessError("评价记录不存在")

            # 验证权限
            if evaluation.coach_id != coach_id:
                raise BusinessError("无权限修改此评价")

            # 验证是否已评价
            if not evaluation.has_coach_evaluation():
                raise BusinessError("您还未提交评价，无法修改")

            # 验证修改时限（24小时内可修改）
            if evaluation.coach_submitted_at:
                time_diff = datetime.now() - evaluation.coach_submitted_at
                if time_diff > timedelta(hours=24):
                    raise BusinessError("评价提交超过24小时，无法修改")

            # 验证评分范围
            if not (1 <= rating <= 5):
                raise ValidationError("评分必须在1-5之间")

            # 更新评价
            evaluation.coach_rating = rating
            evaluation.coach_comment = comment
            evaluation.coach_submitted_at = datetime.now()

            db.session.commit()

            current_app.logger.info(
                f"教练评价修改成功 - 评价ID: {evaluation_id}, 教练ID: {coach_id}"
            )

            return {
                'success': True,
                'evaluation_id': evaluation.id,
                'rating': rating,
                'comment': comment,
                'updated_at': evaluation.coach_submitted_at.isoformat(),
                'message': '评价修改成功'
            }

        except (BusinessError, ValidationError):
            raise
        except SQLAlchemyError as e:
            db.session.rollback()
            current_app.logger.error(
                f"修改教练评价失败 - 评价ID: {evaluation_id}, 错误: {str(e)}"
            )
            raise BusinessError("修改评价失败，请稍后重试")

    @staticmethod
    def get_evaluation_detail(evaluation_id: int, user_id: int) -> Dict[str, Any]:
        """
        获取评价详情

        Args:
            evaluation_id: 评价ID
            user_id: 当前用户ID

        Returns:
            评价详情信息

        Raises:
            BusinessError: 业务逻辑错误
        """
        try:
            # 获取评价记录（包括关联的用户信息）
            evaluation = Evaluation.query.options(
                joinedload(Evaluation.student),
                joinedload(Evaluation.coach)
            ).get(evaluation_id)

            if not evaluation:
                raise BusinessError("评价记录不存在")

            # 验证权限
            if evaluation.student_id != user_id and evaluation.coach_id != user_id:
                raise BusinessError("无权限查看此评价")

            # 获取预约信息（包括关联的球台信息）
            reservation = Reservation.query.options(
                joinedload(Reservation.table),
                joinedload(Reservation.student),
                joinedload(Reservation.coach)
            ).get(evaluation.reservation_id)

            # 计算修改权限
            can_modify_student = (
                evaluation.student_id == user_id and
                evaluation.has_student_evaluation() and
                evaluation.student_submitted_at and
                (datetime.now() - evaluation.student_submitted_at) <= timedelta(hours=24)
            )

            can_modify_coach = (
                evaluation.coach_id == user_id and
                evaluation.has_coach_evaluation() and
                evaluation.coach_submitted_at and
                (datetime.now() - evaluation.coach_submitted_at) <= timedelta(hours=24)
            )

            # 返回字典格式数据
            return {
                'success': True,
                'evaluation': evaluation,
                'reservation': reservation,
                'student': evaluation.student,
                'coach': evaluation.coach,
                'can_modify_student': can_modify_student,
                'can_modify_coach': can_modify_coach,
                'message': '获取评价详情成功'
            }

        except BusinessError:
            raise
        except SQLAlchemyError as e:
            current_app.logger.error(
                f"获取评价详情失败 - 评价ID: {evaluation_id}, 错误: {str(e)}"
            )
            raise BusinessError("获取评价详情失败，请稍后重试")

    @staticmethod
    def get_user_evaluations(user_id: int, user_type: str, page: int = 1,
                           per_page: int = 10, status: str = None) -> Dict[str, Any]:
        """
        获取用户评价列表

        Args:
            user_id: 用户ID
            user_type: 用户类型（student/coach）
            page: 页码
            per_page: 每页数量
            status: 状态过滤（completed/pending）

        Returns:
            评价列表信息

        Raises:
            BusinessError: 业务逻辑错误
        """
        try:
            # 构建查询条件
            if user_type == 'student':
                query = Evaluation.query.filter_by(student_id=user_id)
            elif user_type == 'coach':
                query = Evaluation.query.filter_by(coach_id=user_id)
            else:
                raise ValidationError("无效的用户类型")

            # 状态过滤
            if status == 'completed':
                query = query.filter(
                    and_(
                        Evaluation.student_rating.isnot(None),
                        Evaluation.coach_rating.isnot(None)
                    )
                )
            elif status == 'pending':
                if user_type == 'student':
                    query = query.filter(Evaluation.student_rating.is_(None))
                else:
                    query = query.filter(Evaluation.coach_rating.is_(None))

            # 排序和分页
            query = query.order_by(Evaluation.created_at.desc())
            pagination = query.paginate(
                page=page, per_page=per_page, error_out=False
            )

            # 构建评价列表
            evaluations = []
            for evaluation in pagination.items:
                reservation = Reservation.query.options(
                    joinedload(Reservation.table),
                    joinedload(Reservation.student),
                    joinedload(Reservation.coach)
                ).get(evaluation.reservation_id)

                eval_data = {
                    'id': evaluation.id,
                    'reservation_id': evaluation.reservation_id,
                    'student_id': evaluation.student_id,
                    'coach_id': evaluation.coach_id,
                    'student_rating': evaluation.student_rating,
                    'student_comment': evaluation.student_comment,
                    'student_submitted_at': evaluation.student_submitted_at,
                    'coach_rating': evaluation.coach_rating,
                    'coach_comment': evaluation.coach_comment,
                    'coach_submitted_at': evaluation.coach_submitted_at,
                    'created_at': evaluation.created_at,
                    'is_completed': evaluation.is_completed(),
                    'student_name': evaluation.student.real_name if evaluation.student else '未知学员',
                    'coach_name': evaluation.coach.real_name if evaluation.coach else '未知教练',
                    'student_rating_stars': '★' * (evaluation.student_rating or 0) + '☆' * (5 - (evaluation.student_rating or 0)),
                    'coach_rating_stars': '★' * (evaluation.coach_rating or 0) + '☆' * (5 - (evaluation.coach_rating or 0)),
                    'reservation': {
                        'date': reservation.reservation_date.strftime('%Y年%m月%d日'),
                        'start_time': reservation.start_time.strftime('%H:%M'),
                        'end_time': reservation.end_time.strftime('%H:%M'),
                        'table_name': reservation.table.name if reservation.table else '未知球台'
                    }
                }
                evaluations.append(eval_data)

            return {
                'success': True,
                'evaluations': evaluations,
                'pagination': {
                    'page': page,
                    'per_page': per_page,
                    'total': pagination.total,
                    'pages': pagination.pages,
                    'has_prev': pagination.has_prev,
                    'has_next': pagination.has_next,
                    'prev_num': pagination.prev_num,
                    'next_num': pagination.next_num
                }
            }

        except ValidationError:
            raise
        except SQLAlchemyError as e:
            current_app.logger.error(
                f"获取用户评价列表失败 - 用户ID: {user_id}, 错误: {str(e)}"
            )
            raise BusinessError("获取评价列表失败，请稍后重试")

    @staticmethod
    def get_pending_evaluations(user_id: int, user_type: str) -> List[Dict[str, Any]]:
        """
        获取待评价列表

        Args:
            user_id: 用户ID
            user_type: 用户类型（student/coach）

        Returns:
            待评价列表

        Raises:
            BusinessError: 业务逻辑错误
        """
        try:
            # 构建查询条件 - 查找已完成的课程但用户还未评价的记录
            if user_type == 'student':
                # 学员查看需要自己评价的课程（已完成但学员还未评价）
                query = db.session.query(Reservation).join(
                    Evaluation, Reservation.id == Evaluation.reservation_id, isouter=True
                ).filter(
                    and_(
                        Reservation.student_id == user_id,
                        Reservation.status == 'completed',
                        or_(
                            Evaluation.id.is_(None),  # 还没有评价记录
                            Evaluation.student_rating.is_(None)  # 有评价记录但学员还未评价
                        )
                    )
                )
            elif user_type == 'coach':
                # 教练查看需要自己评价的课程（已完成但教练还未评价）
                query = db.session.query(Reservation).join(
                    Evaluation, Reservation.id == Evaluation.reservation_id, isouter=True
                ).filter(
                    and_(
                        Reservation.coach_id == user_id,
                        Reservation.status == 'completed',
                        or_(
                            Evaluation.id.is_(None),  # 还没有评价记录
                            Evaluation.coach_rating.is_(None)  # 有评价记录但教练还未评价
                        )
                    )
                )
            else:
                raise ValidationError("无效的用户类型")

            # 按时间倒序排列
            reservations = query.order_by(Reservation.reservation_date.desc()).all()

            pending_evaluations = []
            for reservation in reservations:
                # 获取或创建评价记录
                evaluation = Evaluation.query.filter_by(reservation_id=reservation.id).first()
                if not evaluation:
                    # 如果没有评价记录，创建一个
                    evaluation = Evaluation.get_or_create_evaluation(
                        reservation.id, reservation.student_id, reservation.coach_id
                    )
                    db.session.commit()

                # 构建待评价数据
                pending_data = {
                    'reservation_id': reservation.id,
                    'evaluation_id': evaluation.id,
                    'date': reservation.reservation_date.strftime('%Y-%m-%d'),
                    'start_time': reservation.start_time.strftime('%H:%M'),
                    'end_time': reservation.end_time.strftime('%H:%M'),
                    'table_name': reservation.table.name if reservation.table else '未知球台',
                    'price': float(reservation.price) if reservation.price else 0,
                    'student_name': reservation.student.real_name if reservation.student else '未知学员',
                    'coach_name': reservation.coach.real_name if reservation.coach else '未知教练',
                    'can_evaluate': True
                }

                if user_type == 'student':
                    pending_data['can_evaluate'] = evaluation.can_student_evaluate()
                    pending_data['other_party'] = pending_data['coach_name']
                else:
                    pending_data['can_evaluate'] = evaluation.can_coach_evaluate()
                    pending_data['other_party'] = pending_data['student_name']

                if pending_data['can_evaluate']:
                    pending_evaluations.append(pending_data)

            current_app.logger.info(
                f"获取待评价列表成功 - 用户ID: {user_id}, 用户类型: {user_type}, "
                f"数量: {len(pending_evaluations)}"
            )

            return pending_evaluations

        except ValidationError:
            raise
        except SQLAlchemyError as e:
            current_app.logger.error(
                f"获取待评价列表失败 - 用户ID: {user_id}, 错误: {str(e)}"
            )
            raise BusinessError("获取待评价列表失败，请稍后重试")